package com.example.api.mq.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


/**
 * exchange：
 * name：order.direct 从名字看出是和order相关的直连交换机
 * type：
 * direct直连模式(routing key是什么就交给哪个queue)
 * fanout不管用哪个routing key，所有的queue都能收到消息
 * topic主题模式，可以根据routing key进行匹配哪些queue  #匹配0个或多个单词  *必须有一个单词
 * headers（几乎不用）
 * durability： durable持久化  Transient临时的，重启就会消失
 * auto delete： Yes/No  如果该交换机没有绑定**就会自动删除，
 * Internal:  如果是内部的，只能用于内部交换机与交换机的绑定
 */

/**
 * Queue:
 * name: pay.callback
 * type:
 * Durability: 是否持久化
 * auto delete： 没有人监听该队列就会删除
 */

/**
 * exchange和绑定exchange建立多层路由
 * exchange可以绑定queue：
 * routing key（路由key） 直连模式下跟queue的name一样就行
 */
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private AmqpAdmin amqpAdmin;

    /**
     * 创建交换机
     */
    @GetMapping("createExchange")
    public void createExchange(@RequestParam String exchangeName){
        /**
         * String name,  交换机的名字
         * boolean durable,  是否持久化
         * boolean autoDelete, 是否自动删除
         * Map<String, Object> arguments 指定参数
         */
        if (StrUtil.isBlank(exchangeName)){
            exchangeName = "mall-exchange";
        }
        Exchange exchange = new DirectExchange(exchangeName, true, false);
        try{
            amqpAdmin.declareExchange(exchange);
        }catch (Exception e){
            log.error("创建交换机{}失败", exchangeName);
        }
        log.info("创建交换机{}成功",exchangeName);
    }

    /**
     * 创建队列
     */
    @GetMapping("createQueue")
    public void createQueue(@RequestParam String queueName){
        /**
         * String name,  队列名称
         * boolean durable,  是否持久化
         * boolean exclusive, true，只能当前连接使用，应该设置以为false
         * boolean autoDelete,  是否自动删除
         * Map<String, Object> arguments
         */
        if (StrUtil.isBlank(queueName)){
            queueName = "mall-queue";
        }
        Queue queue = new Queue(queueName, true, false, false);
        try{
            amqpAdmin.declareQueue(queue);
        }catch (Exception e){
            log.error("创建队列[{}]失败", queueName);
        }
        log.info("创建队列[{}]成功", queueName);
    }

    /**
     * 绑定关系
     */
    @PostMapping("createBinging")
    public void createBinging(){
        /**
         * String destination, 目的地  主交换机要和谁绑定
         * Binding.DestinationType destinationType,  (QUEUE/EXCHANGE) 目的地类型 被绑定的是交换机还是队列
         * String exchange,  交换机  这是传入的主交换机
         * String routingKey,  路由key
         * Map<String, Object> arguments  自定义参数
         */
        Binding binding = new Binding("mall-queue", Binding.DestinationType.QUEUE,
                "mall-exchange","mall-queue", null);
        try{
            amqpAdmin.declareBinding(binding);
        }catch (Exception e){
            log.error("创建绑定关系失败");
        }
        log.info("创建绑定关系成功");
    }

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 测试发送消息
     * 交换机名，路由key，消息体
     * 交换机会根据路由key决定投递到哪个或哪些queue
     */
    @GetMapping("sendMessage")
    public void sendMessage(){
        String exchangeName = "mall-exchange";
        String routingKey = "mall-queue";
        //消息体为对象，会自动序列化，所有需要实现序列化
        //如果注入自己MessageConverter，就可以实现自己的序列化方式，例如json
        String message = "This is a message test.";
        try{
            /**
             * CorrelationData用来指定消息的唯一id
             */
            rabbitTemplate.convertAndSend(exchangeName, routingKey, message, new CorrelationData(IdUtil.fastSimpleUUID()));
        }catch (Exception e){
            log.error("消息发送失败");
        }
        log.info("消息发送成功");
    }

}
